/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


/*************************************************************************
 * File: exdata.h
 *************************************************************************
 *\author: starlove
 *************************************************************************/

#ifndef __MLSE_CODEC_EXDATA_H__
#define __MLSE_CODEC_EXDATA_H__

#include <codec/codec.h>
#include <codec/exdata_wrapper.h>
#include <platform/memory.h>

#ifdef _COMPILER_GCC_
#ifdef __MLSE_USE_CLASSIC_HASH_MAP__
typedef stdext::hash_map<CODE_HASH_KEY, LPWRAPPER_KEYVALUE_DATA_HEADER, str_hash> MAP_DATAS;
#else	//__MLSE_USE_CLASSIC_HASH_MAP__
typedef std::unordered_map<CODE_HASH_KEY, LPWRAPPER_KEYVALUE_DATA_HEADER> MAP_DATAS;
#endif	//__MLSE_USE_CLASSIC_HASH_MAP__
#else	//_COMPILER_GCC_
typedef stdext::hash_map<CODE_HASH_KEY, LPWRAPPER_KEYVALUE_DATA_HEADER> MAP_DATAS;
#endif	//_COMPILER_GCC_

typedef std::vector<LPWRAPPER_DATA_HEADER> LIST_DATAS;
typedef std::map<void *, CMapData> LIST_MAPS;
typedef std::map<void *, CListData> LIST_LISTS;


class IContainerData: public IExData
{
protected:
    void *GetMapDataPtr(void * pv);
    void *GetListDataPtr(void * pv);

    LIST_MAPS m_mapdatas;
    LIST_LISTS m_listdatas;
};

class CListData: public IContainerData
{
public:
    CListData() {};
    CListData(LPBUFFER_WRAPPER pBuffer);
    ~CListData();
    void Load(LPBUFFER_WRAPPER pBuffer);

    unsigned int GetSize();

    template <typename T>
    T GetNumber(unsigned int i, T def = 0)
    {
        if(i >= m_datas.size())
            return NULL;
        LPWRAPPER_DATA_HEADER pv = m_datas[i];
        T *pt = (T *)(((char *)pv) + sizeof(WRAPPER_DATA_HEADER));
        return *pt;
    };

    ENCODESTR GetString(unsigned int i, const char *szdef = "")
    {
        ENCODESTR sz = (ENCODESTR)GetPtr(i);
        return sz;
    };

    void *GetPtr(unsigned int i)
    {
        if(i >= m_datas.size())
            return NULL;
        LPWRAPPER_DATA_HEADER pv = m_datas[i];
        void *p = (void *)(((char *)pv) + sizeof(WRAPPER_DATA_HEADER));
        return p;
    };

    template <typename T>
    T *GetObjectRef(unsigned int i)
    {
        if(i >= m_datas.size())
            return NULL;
        LPWRAPPER_DATA_HEADER pv = m_datas[i];
        DATA_TP tp = GetDataType<T>();
        switch (tp)
        {
        case DTP_MAP:
        {
            void *p = GetMapDataPtr(pv);
            if(NULL != p)
                return (T*)p;
            return NULL;
        };
        case DTP_LIST:
        {
            void *p = GetListDataPtr(pv);
            if(NULL != p)
                return (T*)p;
            return NULL;
        };
        }
        return NULL;
    };

private:
    LIST_DATAS m_datas;
};

class CMapData: public IContainerData
{
public:
    CMapData() {};
    CMapData(LPBUFFER_WRAPPER pBuffer);
    ~CMapData();
    void Load(LPBUFFER_WRAPPER pBuffer);
    unsigned int GetSize();

    template <typename TK>
    LPWRAPPER_KEYVALUE_DATA_HEADER GetValue(TK k)
    {
        CODE_HASH_KEY pk;
        pk = ConvertToStr<TK>(k);
        if(GetDataType<TK>() != DTP_STR)
        {
            pk += "(v)";
        }
        else
        {
            pk += "(s)";
        }
        MAP_DATAS::iterator it = m_datas.find(pk);
        if (it != m_datas.end())
        {
            return it->second;
        }
        return NULL;
    }

    template <typename TK,typename T>
    T GetNumber(TK k, T def = 0)
    {
        LPWRAPPER_KEYVALUE_DATA_HEADER pv = GetValue<TK>(k);
        if (!pv)
            return def;
        T *pt = (T *)(((char *)pv) + sizeof(WRAPPER_KEYVALUE_DATA_HEADER) + pv->ksize);
        return *pt;
    };

    template <typename TK>
    ENCODESTR GetString(TK k, const char *szdef = "")
    {
        ENCODESTR pt = (ENCODESTR)this->GetPtr<TK>(k);
        if( !pt )
            return szdef;
        return pt;
    };

    template <typename TK>
    void *GetPtr(TK k)
    {

        LPWRAPPER_KEYVALUE_DATA_HEADER pv = GetValue<TK>(k);
        if (pv)
        {
            return (void *)(((char *)pv) + sizeof(WRAPPER_KEYVALUE_DATA_HEADER) + pv->ksize);
        }
        return NULL;
    };

    template <typename TK, typename T>
    T *GetObjectRef(TK k)
    {
        LPWRAPPER_KEYVALUE_DATA_HEADER pv = GetValue<TK>(k);
        if (!pv)
            return NULL;
        DATA_TP tp = GetDataType<T>();
        switch (tp)
        {
        case DTP_MAP:
        {
            void *p = GetMapDataPtr(pv);
            if(NULL != p)
                return (T*)p;
            return NULL;
        };
        case DTP_LIST:
        {
            void *p = GetListDataPtr(pv);
            if(NULL != p)
                return (T*)p;
            return NULL;
        };
        default:{ return NULL; }
        }
        return NULL;
    };

private:
    MAP_DATAS m_datas;
};

#endif
